package gorm_v2

import (
	"gitee.com/youbeiwuhuan/gin-practice/fizz-gorm2/tools/reflects"
	"reflect"
	"strings"
)

const (
	COLUMN     = "column"
	GORM       = "gorm"
	PRIMARYKEY = "primarykey"
)

// CreateEntityAndSetId 创建实体并设置id
// structType  实体结构体类型
// id    目标值
// 返回指向实体
func CreateEntityAndSetId(vstruct interface{}, id interface{}) (val interface{}) {
	if !reflects.IsStruct(vstruct) {
		panic("vstruct is not  a struct")
	}

	rType := reflect.TypeOf(vstruct)

	////返回对象的指针对应的reflect.Value,pVal是一个指针
	pVal := reflect.New(rType)
	//获取真实的结构体值
	tValue := pVal.Elem()

	if ok, name := GetIdFieldName(tValue.Interface()); ok {
		fVal := tValue.FieldByName(name)
		fVal.Set(reflect.ValueOf(id))
	} else {
		panic("can not get id field")
	}

	// 指向Person的指针的接口{}类型（实际上是*Person）
	return tValue.Interface()
}

// SetIdVal   设置id值
func SetIdVal(structPtr interface{}, id int64) bool {

	if !reflects.IsPointerToStruct(structPtr) {
		panic("structPtr is not  a pointer to struct")
	}

	st := reflect.ValueOf(structPtr).Elem()
	if ok, name := GetIdFieldName(structPtr); ok {
		f := st.FieldByName(name)
		f.Set(reflect.ValueOf(id))
		return true
	}

	return false

}

// GetIdFieldName 获取id字段名称
// v 结构体的对象或指针
func GetIdFieldName(v interface{}) (bool, string) {
	st := reflect.TypeOf(v)

	if reflects.IsPointerToStruct(v) {
		st = st.Elem()
	}

	for i, len := 0, st.NumField(); i < len; i++ {
		f := st.Field(i)
		if tagVal, isOk := f.Tag.Lookup(GORM); isOk {
			if existGorm2Tag(PRIMARYKEY, tagVal) {
				return true, f.Name
			}

		}
	}

	return false, ""
}

// GetColumnSql 获取列sql ，如 t.id,t.name,t.age
// v  传空实体类模型
// alia  表别名，可传""
func GetColumnSql(m interface{}, alia string) string {
	if !reflects.IsStruct(m) {
		panic("m is not struct")
	}

	st := reflect.TypeOf(m)

	sb := strings.Builder{}

	for i, len := 0, st.NumField(); i < len; i++ {
		f := st.Field(i)
		if tagVal, isOk := f.Tag.Lookup(GORM); isOk {
			//fmt.Println("--------" + f.Name + " -- " + tagVal)
			col := getGorm2Tag(COLUMN, tagVal)
			if "" == col {
				continue
			}
			sb.WriteString(",")
			if "" != alia {
				sb.WriteString(alia)
				sb.WriteString(".")
			}

			sb.WriteString(col)
		}
	}

	r := sb.String()
	if r != "" {
		return r[1:]
	}

	return ""
}

func existGorm2Tag(name string, tagVal string) bool {

	if "" == tagVal || strings.TrimSpace(tagVal) == "" {
		return false
	}

	tagItems := strings.Split(tagVal, ",")
	for i, len0 := 0, len(tagItems); i < len0; i++ {
		it := tagItems[i]
		if !strings.Contains(it, ":") {
			return it == name
		} else {
			vals := strings.Split(it, ":")
			if name == vals[0] {
				return true
			}
		}
	}

	return false
}

func getGorm2Tag(name string, tagVal string) string {
	if "" == tagVal {
		return ""
	}

	tagItems := strings.Split(tagVal, ",")
	for i, len0 := 0, len(tagItems); i < len0; i++ {
		it := tagItems[i]
		if !strings.Contains(it, ":") {
			continue
		}

		vals := strings.Split(it, ":")
		if name != vals[0] {
			continue
		}

		if len(vals) > 1 {
			return vals[1]
		} else {
			return ""
		}

	}

	return ""
}
